
#ifndef SX_ABSTRACT_RECORDING_H
#define SX_ABSTRACT_RECORDING_H

#include <sxAutoReferenceArrayList.h>

namespace Sx {
namespace Multimedia {

/*
 * Note: When creating a new type of Recorder (by extending AbstractRecorder),
 * the associated recording type does not need to extend this AbstractRecording
 * class; rather it can simply be a typedef:
 * 
 * MyRecorderType : public AbstractRecorder<MyFrameType, int> { .. };
 * typedef AbstractRecording<MyFrameType, int> MyRecordingType;
 */
template <class FrameType, typename Real>
class AbstractRecording {
public:
	AbstractRecording();
	virtual ~AbstractRecording();

	bool setEndTime(Real end);
	void setFPS(unsigned int fps);
	void setFramesPerSecond(unsigned int fps);

	Real length() const;
	Real getEndTime() const;
	unsigned int getFPS() const;
	unsigned int getFramesPerSecond() const;
	unsigned int getFrameCount() const;
	void clear();

	/*
	 * If the internal recording contains data (frame information) and the user
	 * wishes to overwrite existing frames (starting with the provided index),
	 * this function can be used to move the internal freeIndex pointer. This
	 * will change the position in the recording where the next frame is
	 * made available via getNextFrame().
	 */
	bool invalidateGreaterThan(unsigned int index);

	/*
	 * For performance, the recording relies on a recorder implementation to
	 * properly construct the frame data. Frames are not not explicitly stored
	 * (or added) into the frames array, rather they are only accessed by
	 * retrieving a reference to an existing empty frame.
	 */
	FrameType& getNextFrame();

	/* 
	 * Retrieves a frame from this recording. If the index is out of bounds
	 * then this function will return false and the output param frame will not
	 * be modified.
	 */
	bool getFrame(unsigned int index, FrameType& frame);

protected:
	Util::AutoReferenceArrayList<FrameType> frames;

	Real len;
	unsigned int fps;
};

}

}

template <class FrameType, typename Real>
Sx::Multimedia::AbstractRecording<FrameType, Real>::AbstractRecording() {
	this->len = 0;
	this->fps = 0;
}

template <class FrameType, typename Real>
Sx::Multimedia::AbstractRecording<FrameType, Real>::~AbstractRecording() {}

template <class FrameType, typename Real>
bool Sx::Multimedia::AbstractRecording<FrameType, Real>::setEndTime(Real end) {
	this->len = end;
}

template <class FrameType, typename Real>
void Sx::Multimedia::AbstractRecording<FrameType, Real>::setFPS(unsigned int fps) {
	this->fps = fps;
}

template <class FrameType, typename Real>
void Sx::Multimedia::AbstractRecording<FrameType, Real>::setFramesPerSecond(unsigned int fps) {
	this->fps = fps;
}

template <class FrameType, typename Real>
Real Sx::Multimedia::AbstractRecording<FrameType, Real>::length() const {
	return this->len;
}

template <class FrameType, typename Real>
Real Sx::Multimedia::AbstractRecording<FrameType, Real>::getEndTime() const {
	return this->len;
}

template <class FrameType, typename Real>
unsigned int Sx::Multimedia::AbstractRecording<FrameType, Real>::getFPS() const {
	return this->fps;
}

template <class FrameType, typename Real>
unsigned int Sx::Multimedia::AbstractRecording<FrameType, Real>::getFramesPerSecond() const {
	return this->fps;
}

template <class FrameType, typename Real>
unsigned int Sx::Multimedia::AbstractRecording<FrameType, Real>::getFrameCount() const {
	return this->frames.size();
}

template <class FrameType, typename Real>
void Sx::Multimedia::AbstractRecording<FrameType, Real>::clear() {
	this->frames.clear();
}

template <class FrameType, typename Real>
bool Sx::Multimedia::AbstractRecording<FrameType, Real>::invalidateGreaterThan(unsigned int index) {
	return this->frames.invalidateGreaterThan(index);
}

template <class FrameType, typename Real>
FrameType& Sx::Multimedia::AbstractRecording<FrameType, Real>::getNextFrame() {
	return this->frames.getNext();
}

template <class FrameType, typename Real>
bool Sx::Multimedia::AbstractRecording<FrameType, Real>::getFrame(unsigned int index, FrameType& frame) {
	return this->frames.get(index, frame);
}

#endif
